//
//  AppController.m
//  CocoaFan
//
//  Created by Chen Xianan on 2009-02-16.
//  Copyright 2009 realazy.org All rights reserved.
//

#import "AppController.h"
#import "MGTwitterEngine+CocoaFan.h"
#import "COCOAFANTableView.h"
#import "COCOAFANCell.h"
#import "COCOAFANViewController.h"
#import "IFVerticallyExpandingTextField.h"
#import "COCOAFANFormatter.h"
#import "COCOAFANMessageBoardView.h"
#import "COCOAFANPmsgWindowController.h"

#define INIT_REPLIES_COUNT 10
#define INIT_PMSG_COUNT 10

NSString * const kCOCOAFAN_USERNAME = @"username";
NSString * const kCOCOAFAN_PASSWORD = @"password";
NSString * const kCOCOAFAN_AUTOLOGIN = @"autologin";
NSString * const kCOCOAFAN_STARTATLOGIN = @"startatlogin";
NSString * const kCOCOAFAN_UPDATE_INTERVAL = @"update_interval";
NSString * const kCOCOAFAN_USE_GROWL = @"use_growl_notification";

static int reply_count = INIT_REPLIES_COUNT;
static int dmsg_count = INIT_PMSG_COUNT;
static BOOL firstload = YES;
static BOOL needsReloadData = YES;

static NSString *replyToID = @"";
static NSString *currentDeleteID = @"";
static NSString *currentStatusID = @"";
static int currentDirectID = 0;
static NSString *growlShowNewStatuses = @"show_new_statuses";

enum {
	COCOAFAN_REQ_FRD = 0,
	COCOAFAN_REQ_REP,
	COCOAFAN_REQ_PMSG
};

static BOOL responses[3] = {NO, NO, NO};

NSInteger COCOAFAN_SORT_STATUS(NSDictionary *item1, NSDictionary *item2, void *context)
{
	return [[item2 objectForKey:@"created_at"] compare:[item1 objectForKey:@"created_at"]];
}

@implementation AppController

@synthesize userInfo;

+ (void)initialize
{
	NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
	[defaultValues setObject:@"" forKey:kCOCOAFAN_USERNAME];
	[defaultValues setObject:@"" forKey:kCOCOAFAN_PASSWORD];
	[defaultValues setObject:[NSNumber numberWithBool:NO] forKey:kCOCOAFAN_AUTOLOGIN];
	[defaultValues setObject:[NSNumber numberWithBool:NO] forKey:kCOCOAFAN_STARTATLOGIN];
	[defaultValues setObject:[NSNumber numberWithInteger:120] forKey:kCOCOAFAN_UPDATE_INTERVAL];
	[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues];

}

+ (NSString *)readableDate:(NSDate *)date
{
	NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:date];
	if (interval < 5){
		return [NSString stringWithString:NSLocalizedString(@"JUST_NOW", @"Just now")];
	} 
	if (interval < 60){
		return [NSString stringWithFormat:NSLocalizedString(@"SECONDS_AGO", @"%d seconds ago"), (int)(ceil(interval))];
	} 
	if (interval < 150){
		return [NSString stringWithString:NSLocalizedString(@"1MINUTE_AGO", @"1 minute ago")];
	}
	if (interval < 3600){
		return [NSString stringWithFormat:NSLocalizedString(@"MINUTES_AGO", @"%d minutes ago"), (int)(ceil(interval/60.0))];
	}
	if (interval < 3600 * 1.5){
		return [NSString stringWithString:NSLocalizedString(@"1HOUR_AGO", @"1 hour ago")];
	}
	if (interval < 3600 * 24){
		return [NSString stringWithFormat:NSLocalizedString(@"HOURS_AGO", @"%d hours ago"), (int)(ceil(interval/3600.0))];
	}
	if (interval < 3600 * 24 * 2){
		return [NSString stringWithString:NSLocalizedString(@"YESTERDAY", @"yesterday")];
	} 
	
	return [date descriptionWithCalendarFormat: @"%Y-%m-%d %H:%M:%S"
									  timeZone:nil
										locale:[NSLocale currentLocale]];
}

+ (void)openMessageInBrowser:(NSDictionary *)dic
{
	NSString *prefix;
	if ([[dic objectForKey:@"type"] intValue] == COCOAFAN_STATUS_PMSG)
		prefix = @"http://fanfou.com/privatemsg.reply/";
	else
		prefix = @"http://fanfou.com/statuses/";

	NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", prefix, [dic objectForKey:@"id"]]];
	[[NSWorkspace sharedWorkspace] openURL:url];
}

+ (void)openProfileInBrowser:(NSDictionary *)dic
{
	NSString *key;
	if ([[dic objectForKey:@"type"] intValue] == COCOAFAN_STATUS_PMSG)
		key = @"sender";
	else
		key = @"user";

	NSURL *url = [NSURL URLWithString:[[dic objectForKey:key] objectForKey:@"url"]];
	[[NSWorkspace sharedWorkspace] openURL:url];
}

- (id)init
{
	if (!(self = [super init])) return nil;
	
	engine = [[MGTwitterEngine alloc] initWithDelegate:self];
	[engine setUsesSecureConnection:NO];
	statusesArray = [[NSMutableArray alloc] initWithCapacity:0];
	tmpStatuses = [[NSMutableArray alloc] initWithCapacity:0];
	isLogined = NO;
	currentStatusID = @"";
	currentDirectID = 0;
	cacheCells = [[NSMutableDictionary alloc] initWithCapacity:0];

	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	[nc addObserver:self
		   selector:@selector(handleReply:)
			   name:COCOAFANReplyNotification
			 object:nil];
	[nc addObserver:self
		   selector:@selector(handlePmsg:)
			   name:COCOAFANPmsgNotification
			 object:nil];
	[nc addObserver:self
		   selector:@selector(handleSendPmsg:)
			   name:COCOAFANSendPmsgNotification
			 object:nil];
	[nc addObserver:self
		   selector:@selector(handleForward:)
			   name:COCOAFANForwardNotification
			 object:nil];
	[nc addObserver:self
		   selector:@selector(handleDelete:)
			   name:COCOAFANDeleteNotification
			 object:nil];

	return self;
}

- (void)dealloc
{
	[loginUUID release];
	[sendUUID release];
	[frdTimelineUUID release];
	[userInfoUUID release];
	[repliesUUID release];
	[directUUID release];
	[deleteUUID release];
	[sendPmsgUUID release];

	[engine release];
	[statusesArray release];
	[statusesArrayClone release];
	[selectedStatusContent release];
	[tmpStatuses release];
	[cacheCells release];
	[userInfo release];
	[timer invalidate];
	[pmsgController release];
	
	[[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

- (void)awakeFromNib
{
	COCOAFANFormatter *formatter = [[[COCOAFANFormatter alloc] init] autorelease];
	[textInput setFormatter:formatter];
	[table setDelegate:self];
	[table setDataSource:self];
	[table setIntercellSpacing:NSMakeSize(0.0, 12.0)];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	NSString *_username = [defaults stringForKey:kCOCOAFAN_PASSWORD];
	NSString *_password = [defaults stringForKey:kCOCOAFAN_USERNAME];
	if ([defaults boolForKey:kCOCOAFAN_AUTOLOGIN]
		&& [_username length]
		&& [_password length]){
		[engine setUsername:_username password:_password];
		[loginUUID release];
		loginUUID = [[engine checkUserCredentials] retain];
		//[msgBoard ]
	} else {
		[msgField setStringValue:NSLocalizedString(@"LOGIN_TIP", @"Please sign in using your Fanfou account information.")];
		[msgField setTextColor:[NSColor blackColor]];
		[self showSheet:loginSheet];
	}
	[GrowlApplicationBridge setGrowlDelegate:self];
}

- (NSArray *)uniqArray:(NSArray *)array
{
	NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:0];
	NSMutableDictionary *done = [[NSMutableDictionary alloc] initWithCapacity:0];
	for (NSDictionary *dic in array){
		NSString *key = [dic objectForKey:@"id"];
		if (![[done objectForKey:key] boolValue]){
			[done setObject:[NSNumber numberWithBool:YES] forKey:key];
			[ret addObject:dic];
		}
	}
	[done release];

	return [ret autorelease];
}

- (void)handleReceiveItems:(NSArray *)items
{
	for (NSDictionary *dic in items){
		[tmpStatuses addObject:[self transformStatus:dic]];
	}
	//[tmpStatuses addObjectsFromArray:items];
	if ([items count]) needsReloadData = YES;
}

- (COCOAFAN_STATUS_TYPE)statusType:(NSDictionary *)statusItem
{
	NSString *uid = [userInfo objectForKey:@"id"];

	if ([statusItem objectForKey:@"sender"])
		return COCOAFAN_STATUS_PMSG;

	if ([[statusItem objectForKey:@"in_reply_to_user_id"]
			 isEqualToString:uid])
		return COCOAFAN_STATUS_REPLY;

	if ([[[statusItem objectForKey:@"user"] objectForKey:@"id"]
			isEqualToString:uid])
		return COCOAFAN_STATUS_OWN;

	return COCOAFAN_STATUS_NORMAL;
}

- (BOOL)allRequestsReturned
{
	int i = 0;
	for (; i<3; i++)
		if (responses[i] == NO) return NO;
	
	return YES;
}

- (void)handleIdentifier:(NSString *)identifier
				andItems:(NSArray *)items
{
	if ([identifier isEqualToString:frdTimelineUUID]){
		responses[COCOAFAN_REQ_FRD] = YES;
	} else if ([identifier isEqualToString:repliesUUID]){
		responses[COCOAFAN_REQ_REP] = YES;
		reply_count = 0;
	} else if ([identifier isEqualToString:directUUID]){
		responses[COCOAFAN_REQ_PMSG] = YES;
		dmsg_count = 0;
	}

	if ([items count]) [self handleReceiveItems:items];

	if (firstload){
		if ([tmpStatuses count] > 0){
			[statusesArray addObjectsFromArray:tmpStatuses];
			NSArray *tmpItems = [self uniqArray:statusesArray];
			[statusesArray removeAllObjects];
			[statusesArray addObjectsFromArray:tmpItems];
			[statusesArray sortUsingFunction:COCOAFAN_SORT_STATUS context:NULL];
			[table reloadData];
			needsReloadData = YES;
			[tmpStatuses removeAllObjects];
			NSInteger row = [table selectedRow];
			if ([statusesArray count] > 0){
				[selectedStatusContent release];
				selectedStatusContent = [[statusesArray objectAtIndex:row] retain];
			} else {
				selectedStatusContent = nil;
			}
		}
	}
	
	if ([self allRequestsReturned]){
		if (!firstload) [self updateReadableDate];
		if (needsReloadData){
			if (!firstload){
				NSArray *uniqItems = [self uniqArray:tmpStatuses];
				[statusesArray addObjectsFromArray:uniqItems];
				[statusesArray sortUsingFunction:COCOAFAN_SORT_STATUS context:NULL];
				[table reloadData];
				NSInteger row = [table selectedRow] + [uniqItems count];
				[table selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
				   byExtendingSelection:NO];
				//[table scrollRowToVisible:row];
				if (![NSApp isActive])
					[NSApp requestUserAttention:NSInformationalRequest];
				for (NSDictionary *dic in tmpStatuses){
					[GrowlApplicationBridge
							notifyWithTitle:[dic objectForKey:@"screen_name"]
								description:[dic objectForKey:@"textString"]
						   notificationName:growlShowNewStatuses
								   iconData:nil
								   priority:0
								   isSticky:NO
							   clickContext:nil];
				}
			}
			currentStatusID = [self findCurrentStatusID];
			NSLog(@"all returned currentStatusID:%@", currentStatusID);
		}
		firstload = NO;
		[msgBoard hide];
		int i = 0;
		for (; i<3; i++)
			responses[i] = NO;

		[self resetTimer];
		
		[tmpStatuses removeAllObjects];

	}
}

- (NSDictionary *)findStatusByID:(NSString *)status_id
{
	for (NSDictionary *dic in statusesArray)
		if ([[dic objectForKey:@"id"] isEqualToString:status_id])
			return [[dic retain] autorelease];

	return nil;
}

- (COCOAFANCell *)cellByID:(NSString *)status_id
{
	if (![cacheCells objectForKey:status_id]){
		NSDictionary *status = [self findStatusByID:status_id];
		COCOAFANCell *cell = [[COCOAFANCell alloc] initWithStatusContent:status];
		[cacheCells setObject:cell forKey:status_id];
		[cell release];
	}
	
	return [cacheCells objectForKey:status_id];
}

- (NSInteger)findRowByID:(NSString *)status_id
{
	NSInteger i = 0;
	for (NSDictionary *dic in statusesArray){
		if ([[dic objectForKey:@"id"] isEqualToString:status_id])
			return i;
		i++;
	}
	return -1;
}

- (NSString *)findCurrentStatusID
{
	for (NSDictionary *dic in statusesArray){
		if (![dic objectForKey:@"sender_id"]){
			return [dic objectForKey:@"id"];
		}
	}
	return @"";
}

- (void)updateReadableDate
{
	for (NSMutableDictionary *dic in statusesArray){
		NSMutableAttributedString *attrMsg = [[NSMutableAttributedString alloc] initWithAttributedString:[dic objectForKey:@"attributedText"]];
		[attrMsg appendAttributedString:[self _attributedAdditionalInformation:dic]];
		[dic setObject:attrMsg forKey:@"attributedMessage"];
		[attrMsg release];
	}
}

- (void)focusTextField:(NSTextField *)textField
{
	NSLog(@"f: %@, cur:%@", [window firstResponder], [textField currentEditor]);
	if ([window firstResponder] != [textField currentEditor])
		[window makeFirstResponder:[textField currentEditor]];
	
	NSTextView *editor = (NSTextView *)[textField currentEditor];
	[editor setSelectedRange:NSMakeRange([[textField stringValue] length], 0)];
}

- (void)resetTimer
{
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	NSInteger interval = [defaults integerForKey:kCOCOAFAN_UPDATE_INTERVAL];
	[timer invalidate];
	timer = [[NSTimer scheduledTimerWithTimeInterval:interval
											  target:self 
											selector:@selector(loadStatuses)
											userInfo:nil
											 repeats:NO] retain];
}

#pragma mark handle notifications

- (void)handleReply:(NSNotification *)note
{
	NSDictionary *statusContent = [note userInfo];
	if (statusContent == nil) return;
	NSString *screenName = [statusContent objectForKey:@"screen_name"];
	replyToID = [statusContent objectForKey:@"id"];
	NSString *at = [NSString stringWithFormat:@"@%@ ", screenName];
	NSString *strVal = [NSString stringWithFormat:@"%@%@", at, [textInput stringValue]];
	[textInput setStringValue:strVal];
	[self focusTextField:textInput];
}

- (void)handlePmsg:(NSNotification *)note
{
	NSDictionary *statusContent = [note userInfo];
	if (statusContent == nil) return;
	if (!pmsgController) pmsgController = [[COCOAFANPmsgWindowController alloc] init];
	NSString *screenName = [statusContent objectForKey:@"screen_name"];
	NSString *tip = [NSString stringWithFormat:NSLocalizedString(@"PMSG_TIP_TO", @"Send message to %@"), screenName];
	[pmsgController setStatusContent:statusContent];
	[pmsgController showTip:tip
					   type:COCOAFAN_PMSGTIP_NORMAL];
	[pmsgController showWindow:self];
}

- (void)handleSendPmsg:(NSNotification *)note
{
	NSDictionary *info = [note userInfo];
	NSString *message = [info objectForKey:@"message"];
	NSString *userid = [info objectForKey:@"userid"];
	int msgid = [[info objectForKey:@"in_reply_to_id"] intValue];
	[sendPmsgUUID release];
	sendPmsgUUID = [[engine sendFanfouPrivateMessage:message
												  to:userid
										   inReplyTo:msgid] retain];
}

- (void)handleForward:(NSNotification *)note
{
	NSDictionary *statusContent = [note userInfo];
	if (statusContent == nil) return;
	NSString *screenName = [statusContent objectForKey:@"screen_name"];
	NSString *text = [[statusContent objectForKey:@"attributedText"] string];
	NSString *input = [NSString stringWithFormat:NSLocalizedString(@"VIA", "RT @%@: %@"), screenName, text];
	[textInput setStringValue:input];
	[self focusTextField:textInput];
}

- (void)handleDelete:(NSNotification *)note
{
	NSDictionary *statusContent = [note userInfo];
	currentDeleteID = [statusContent objectForKey:@"id"];
	[deleteUUID release];
	deleteUUID = [[engine deleteFanfouUpdate:currentDeleteID] retain];
	[msgBoard setMessage:NSLocalizedString(@"MSG_DELETING", @"Deleting message...")];
	[msgBoard showWithIndicator];
}

- (NSDictionary *)transformStatus:(NSDictionary *)dic
{
	NSAttributedString *attrStr = [self _attributedText:dic];
	COCOAFAN_STATUS_TYPE type = [self statusType:dic];
	NSDictionary *user;
	id title;
	NSNumber *isPrivateMessage;
	NSString *userid;
	NSString *screen_name;
	if (type == COCOAFAN_STATUS_PMSG){
		user = [dic objectForKey:@"sender"];
		userid = [user objectForKey:@"id"];
		screen_name = [user objectForKey:@"screen_name"];
		NSString *name = [NSString stringWithFormat:@" %@", screen_name];
		NSString *imgName = @"dmsg.png";
		NSFileWrapper *fwrap = [[[NSFileWrapper alloc] initRegularFileWithContents:[[NSImage imageNamed:imgName] TIFFRepresentation]] autorelease];
		[fwrap setFilename:imgName];
		[fwrap setPreferredFilename:imgName];
		NSTextAttachment * ta = [[[NSTextAttachment alloc] initWithFileWrapper:fwrap] autorelease];
		title = (NSMutableAttributedString *)[NSMutableAttributedString attributedStringWithAttachment:ta];
		[title appendAttributedString:[[[NSAttributedString alloc] initWithString:name] autorelease]];
		isPrivateMessage = [NSNumber numberWithBool:YES];
	} else {
		user = [dic objectForKey:@"user"];
		userid = [dic objectForKey:@"id"];
		screen_name = [user objectForKey:@"screen_name"];
		title = (NSString *)screen_name;
		isPrivateMessage = [NSNumber numberWithBool:NO];
	}
	NSURL *imageURL = [NSURL URLWithString:[user objectForKey:@"profile_image_url"]];
	NSImage *avatar = [[NSImage alloc] initWithContentsOfURL:imageURL];
	[avatar setSize:NSMakeSize(COCOAFAN_CELL_AVATARWIDTH, COCOAFAN_CELL_AVATARHEIGHT)];
	NSMutableAttributedString *attributedMessage = [[NSMutableAttributedString alloc] initWithAttributedString:attrStr];
	[attributedMessage appendAttributedString:[self _attributedAdditionalInformation:dic]];
	NSTextFieldCell *statusCell = [[NSTextFieldCell alloc] init];
	[statusCell setAttributedStringValue:attributedMessage];
	[statusCell setWraps:YES];
	BOOL canDelete_bool = [[user objectForKey:@"id"] isEqualToString:[userInfo objectForKey:@"id"]];
	NSNumber *canDelete = [NSNumber numberWithBool:canDelete_bool];

	NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithDictionary:dic];
	NSDictionary *tmpDic = [[NSDictionary alloc] initWithObjectsAndKeys:
		[NSNumber numberWithBool:NO], @"read",
		[NSNumber numberWithInt:type], @"type",
		userid, @"userid",
		screen_name, @"screen_name",
		title, @"title",
		avatar, @"avatar",
		attrStr, @"attributedText",
		[attrStr string], @"textString",
		attributedMessage, @"attributedMessage",
		statusCell, @"statusCell",
		canDelete, @"canDelete",
		isPrivateMessage, @"isPrivateMessage", nil];
	[ret addEntriesFromDictionary:tmpDic];
	[tmpDic release];	
	[statusCell release];
	[avatar release];

	return [ret autorelease];
}

- (NSAttributedString *)_attributedText:(NSDictionary *)dic
{
	NSData *strData = [[dic objectForKey:@"text"] dataUsingEncoding:NSUnicodeStringEncoding];
	NSDictionary *optAttr = [NSDictionary dictionaryWithObjectsAndKeys:
		[NSNumber numberWithInt:NSUnicodeStringEncoding], NSCharacterEncodingDocumentAttribute, nil];
	NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithHTML:strData options:optAttr documentAttributes:nil];
	NSMutableParagraphStyle *pstyle = [[NSMutableParagraphStyle alloc] init];
	[pstyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
	[pstyle setMinimumLineHeight:12.0*1.3];
	
	NSDictionary *stdAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
		[NSFont fontWithName:@"Helvetica" size:12.0], NSFontAttributeName,
		pstyle, NSParagraphStyleAttributeName, nil];
	[attrStr addAttributes:stdAttributes range:NSMakeRange(0, [attrStr length])];
	[pstyle release];

	return [attrStr autorelease];
}

- (NSAttributedString *)_attributedAdditionalInformation:(NSDictionary *)dic
{
	NSString *readableDate = [AppController readableDate:[dic objectForKey:@"created_at"]];
	NSString *source = [dic objectForKey:@"source"];
	if ([source isEqualToString:@""]) source = NSLocalizedString(@"WEB", @"Web");
	NSString *addtionalInfo = source ? [NSString stringWithFormat:@"%@ %@%@", readableDate, NSLocalizedString(@"FROM", @"From "), source] : readableDate;
	addtionalInfo = [NSString stringWithFormat:@"&nbsp; %@", addtionalInfo];
	NSData *strData = [addtionalInfo dataUsingEncoding:NSUnicodeStringEncoding];
	NSDictionary *optAttr = [NSDictionary dictionaryWithObjectsAndKeys:
		[NSNumber numberWithInt:NSUnicodeStringEncoding], NSCharacterEncodingDocumentAttribute, nil];
	NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithHTML:strData options:optAttr documentAttributes:nil];
	NSDictionary *stdAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
		[NSFont fontWithName:@"Helvetica" size:11.0], NSFontAttributeName,
		[NSColor darkGrayColor], NSForegroundColorAttributeName, nil];
	[attrStr addAttributes:stdAttributes range:NSMakeRange(0, [attrStr length])];

	return [attrStr autorelease];
}

- (void)selectedRowAndScrollToVisible
{
	if (!selectedStatusContent) return;
	NSInteger row = [self findRowByID:[selectedStatusContent objectForKey:@"id"]];
	if (row == -1) return;
	[table selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
	   byExtendingSelection:NO];
	[table scrollRowToVisible:row];
}

- (void)filterByString:(NSString *)str
{
	[statusesArray removeAllObjects];
	for (NSDictionary *dic in statusesArrayClone){
		if ([[dic objectForKey:@"screen_name"] rangeOfString:str options:NSCaseInsensitiveSearch].location != NSNotFound ||
			[[dic objectForKey:@"textString"] rangeOfString:str options:NSCaseInsensitiveSearch].location != NSNotFound){
			[statusesArray addObject:dic];
		}
	}
	[table reloadData];
	[self selectedRowAndScrollToVisible];
}

#pragma mark IBActions
- (IBAction)login:(id)sender
{
	NSString *_username = [username stringValue];
	NSString *_password = [password stringValue];
	[engine setUsername:_username password:_password];
	[loginUUID release];
	loginUUID = [[engine checkUserCredentials] retain];
	[self hideSheet:loginSheet];
	[msgBoard setMessage:NSLocalizedString(@"LOGIN_PROGRESS", "Logining into Fanfou...")];
	[msgBoard showWithIndicator];
}

- (IBAction)terminateApp:(id)sender
{
	[self hideSheet:loginSheet];
	[NSApp terminate:sender];
}

- (IBAction)reply:(id)sender
{
	[[NSNotificationCenter defaultCenter]
		postNotificationName:COCOAFANReplyNotification
					  object:self
					userInfo:selectedStatusContent];
}

- (IBAction)pmsg:(id)sender
{
	[[NSNotificationCenter defaultCenter]
		postNotificationName:COCOAFANPmsgNotification
					  object:self
					userInfo:selectedStatusContent];
}

- (IBAction)forward:(id)sender
{
	[[NSNotificationCenter defaultCenter]
		postNotificationName:COCOAFANForwardNotification
					  object:self
					userInfo:selectedStatusContent];
}

- (IBAction)delete:(id)sender
{	
[[NSNotificationCenter defaultCenter]
		postNotificationName:COCOAFANDeleteNotification
					  object:self
					userInfo:selectedStatusContent];
}

- (IBAction)openMessageInBrowser:(id)sender
{
	[AppController openMessageInBrowser:selectedStatusContent];
}

- (IBAction)openProfileInBrowser:(id)sender
{
	[AppController openProfileInBrowser:selectedStatusContent];
}

- (IBAction)refresh:(id)sender
{
	[timer invalidate];
	[self loadStatuses];
}

- (IBAction)changeLogin:(id)sender
{
	[statusesArray removeAllObjects];
	[table reloadData];
	[timer invalidate];
	firstload = YES;
	isLogined = NO;
	
	int i = 0;
	for (; i<3; i++)
		responses[i] = NO;
	
	currentStatusID = @"";
	currentDirectID = 0;
	reply_count = INIT_REPLIES_COUNT;
	dmsg_count = INIT_PMSG_COUNT;

	[msgField setStringValue:NSLocalizedString(@"LOGIN_TIP", @"Please sign in using your Fanfou account information.")];
	[msgField setTextColor:[NSColor blackColor]];
	[self showSheet:loginSheet];
}

- (IBAction)updateFilter:(id)sender
{
	NSString *searchStr = [searchField stringValue];
	if ([searchStr length] == 0){
		[statusesArray removeAllObjects];
		[statusesArray addObjectsFromArray:statusesArrayClone];
		[table reloadData];
		[self selectedRowAndScrollToVisible];
		[self resetTimer];
		[self updateReadableDate];
	} else {
		[self filterByString:searchStr];
	}
}

- (void)showSheet:(NSWindow *)sheetWindow
{
	[NSApp beginSheet:sheetWindow
	   modalForWindow:window
		modalDelegate:nil
	   didEndSelector:NULL
		  contextInfo:NULL];
}

- (void)hideSheet:(NSWindow *)sheetWindow
{
	[NSApp endSheet:sheetWindow];
	[sheetWindow orderOut:self];
}

- (void)loadStatuses
{
	[msgBoard setMessage:NSLocalizedString(@"FETCHING_PROGRESS", "Fetching messages from Fanfou...")];
	[msgBoard showWithIndicator];
	needsReloadData = NO;
	[frdTimelineUUID release];
	frdTimelineUUID = [[engine getFanfouFollowedTimelineSinceID:currentStatusID count:0] retain];
	[repliesUUID release];
	repliesUUID = [[engine getFanfouRepliesSinceID:currentStatusID count:reply_count] retain];
	[directUUID release];
	directUUID = [[engine getFanfouDirectMessagesSinceID:currentDirectID count:dmsg_count] retain];
}

- (void)sendStatus
{
	[sendUUID release];
	sendUUID = [[engine sendFanfouUpdate:[textInput stringValue] inReplyTo:replyToID] retain];
	[textInput setEnabled:NO];
	[msgBoard setMessage:NSLocalizedString(@"SEND_TIP", @"Sending Message to Fanfou")];
	[msgBoard showWithIndicator];
}

#pragma mark NSTextField delegate
- (BOOL)control:(NSControl *)control
textShouldBeginEditing:(NSText *)fieldEditor
{
	if (control == searchField){
		statusesArrayClone = nil;
		[statusesArrayClone release];
		statusesArrayClone = [[NSArray alloc] initWithArray:statusesArray];
		[timer invalidate];
	}
	return YES;
}

- (void)controlTextDidChange:(NSNotification *)aNotification
{
	if ([[aNotification userInfo] objectForKey:@"NSFieldEditor"] == [textInput currentEditor]){
		int num = [[textInput stringValue] length];
		if (num > 100){
			[msgBoard setMessage:[NSString stringWithFormat:NSLocalizedString(@"TEXT_REMAINING", @"%d characters remaining..."), 140 - num]];
			[msgBoard show];
		} else {
			if ([msgBoard alphaValue] != 0) [msgBoard hide];
		}
	}
}

- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
	if ([[aNotification userInfo] objectForKey:@"NSFieldEditor"] == [textInput currentEditor]){
		NSNumber *textMovement = [[aNotification userInfo] objectForKey:@"NSTextMovement"];
		if ([textMovement intValue] == 16){
			[self sendStatus];
		}
	}
}

#pragma mark NSTableView Delegate Methods

- (NSCell *)tableView:(NSTableView *)tableView
dataCellForTableColumn:(NSTableColumn *)tableColumn
				  row:(NSInteger)row
{
	if ([statusesArray count] == 0) return nil;
	NSString *status_id = [[statusesArray objectAtIndex:row] objectForKey:@"id"];
	COCOAFANCell *cell = [self cellByID:status_id];
	if (row == [tableView selectedRow]) [cell setSelected:YES];
	else [cell setSelected:NO];

	return cell;
}

- (CGFloat)tableView:(NSTableView *)tableView
		 heightOfRow:(NSInteger)row
{
	if ([statusesArray count] == 0) return 0.0;
	float width = [[[tableView tableColumns] objectAtIndex:0] width] - COCOAFAN_CELL_OCCUPIEDWIDTH;
	NSTextFieldCell *statusCell = [[statusesArray objectAtIndex:row] objectForKey:@"statusCell"];
	float height = [statusCell cellSizeForBounds:NSMakeRect(0, 0, width, FLT_MAX)].height;
	return height + COCOAFAN_CELL_OCCUPIEDHEIGHT;
}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
	NSInteger row = [table selectedRow];
	if ([statusesArray count] > 0){
		[selectedStatusContent release];
		selectedStatusContent = [[statusesArray objectAtIndex:row] retain];
	} else {
		selectedStatusContent = nil;
	}
}
 

#pragma mark NSTableView DataSource Methods
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
	return [statusesArray count];
}

// - (id)tableView:(NSTableView *)aTableView
//  objectValueForTableColumn:(NSTableColumn *)aTableColumn
//  row:(NSInteger)rowIndex
// {
// 	return [[statusesArray objectAtIndex:rowIndex] objectForKey:@"text"];
// }

#pragma mark NSWindow delegate
- (void)windowDidResize:(NSNotification *)notification
{
	[table reloadData];
}

- (BOOL)windowShouldClose:(id)win
{
	[NSApp hide:self];
	return NO;
}

#pragma mark NSApp Delegate
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication
					hasVisibleWindows:(BOOL)flag
{
	[NSApp unhide:self];
	return YES;
}

#pragma mark MGTwitterEngineDelegate methods

- (void)requestSucceeded:(NSString *)requestIdentifier
{
    //NSLog(@"Request succeeded (%@)", requestIdentifier);
	if ([requestIdentifier isEqualToString:loginUUID]){
		[userInfoUUID release];
		userInfoUUID = [[engine getUserInformationFor:[engine username]] retain];
	} else if ([requestIdentifier isEqualToString:sendUUID]){
		[textInput setStringValue:@""];
		[textInput setEnabled:YES];
		[window makeFirstResponder:textInput];
		[msgBoard setMessage:NSLocalizedString(@"SENT_OK", @"Message sent")];
		[msgBoard scheduledHide:2];
		//[self refresh:nil];
	} else if ([requestIdentifier isEqualToString:deleteUUID]){
		[statusesArray removeObjectAtIndex:[self findRowByID:currentDeleteID]];
		[table reloadData];
		[msgBoard setMessage:NSLocalizedString(@"MSG_DELETE_OK", @"Message is deleted")];
		[msgBoard scheduledHide:2];
		NSInteger row = [table selectedRow];
		if ([statusesArray count] > 0){
			[selectedStatusContent release];
			selectedStatusContent = [[statusesArray objectAtIndex:row] retain]; 
			currentStatusID = [self findCurrentStatusID];
		} else {
			selectedStatusContent = nil;
		}
	} else if ([requestIdentifier isEqualToString:sendPmsgUUID]){
		[pmsgController showTip:NSLocalizedString(@"PMSG_OK", @"send message successfully")
						   type:COCOAFAN_PMSGTIP_NORMAL];
		NSTextField *field = [pmsgController msgField];
		[field setStringValue:@""];
		[field setEnabled:YES];
		[[pmsgController counter] setStringValue:@"0"];
		[pmsgController scheduledCloseWindow:2.0];
	}
}

- (void)requestFailed:(NSString *)requestIdentifier withError:(NSError *)error
{
    // NSLog(@"Twitter request failed! (%@) Error: %@ (%@)", 
    //       requestIdentifier,
    //       [error localizedDescription],
    //       [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
	[self handleIdentifier:requestIdentifier
				  andItems:nil];
	if ([requestIdentifier isEqualToString:loginUUID] || [requestIdentifier isEqualToString:userInfoUUID]){
		NSString *msg = [requestIdentifier isEqualToString:loginUUID] ? NSLocalizedString(@"LOGIN_ERR", @"Account/password invalid") : NSLocalizedString(@"GET_URSERINFO_ERR", @"fail to fetch user info");
		[msgField setStringValue:msg];
		[msgField setTextColor:[NSColor redColor]];
		[msgBoard hide];
		[self showSheet:loginSheet];
	} else if ([requestIdentifier isEqualToString:sendUUID]){
		[textInput setEnabled:YES];
		[window makeFirstResponder:textInput];
		[msgBoard setWarningMessage:NSLocalizedString(@"SEND_ERROR", @"Send fail...")];
	} else if ([requestIdentifier isEqualToString:deleteUUID]){
		[msgBoard setWarningMessage:NSLocalizedString(@"MSG_DELETE_ERR", @"Fail to delete message")];
	} else if ([requestIdentifier isEqualToString:sendPmsgUUID]){
		[[pmsgController msgField] setEnabled:YES];
		[pmsgController showTip:NSLocalizedString(@"PMSG_FAIL", @"Send message fail...")
						   type:COCOAFAN_PMSGTIP_WARNING];
	}
}


- (void)statusesReceived:(NSArray *)statuses forRequest:(NSString *)identifier
{
    //NSLog(@"Got statuses:\r%@", statuses);
	[self handleIdentifier:identifier
				  andItems:statuses];
}


- (void)directMessagesReceived:(NSArray *)messages forRequest:(NSString *)identifier
{
    //NSLog(@"Got direct messages:\r%@", messages);
	[self handleIdentifier:identifier
				  andItems:messages];
	if ([messages count])
		currentDirectID = [[[messages objectAtIndex:0] objectForKey:@"id"] intValue];
}


- (void)userInfoReceived:(NSArray *)userInfo_ forRequest:(NSString *)identifier
{
    //NSLog(@"Got user info:\r%@", userInfo_);
	NSDictionary *info = [userInfo_ objectAtIndex:0];
	NSMutableDictionary *tmp = [NSMutableDictionary dictionaryWithDictionary:info];
	NSURL *imageURL = [NSURL URLWithString:[info objectForKey:@"profile_image_url"]];
	NSImage *avatar = [[NSImage alloc] initWithContentsOfURL:imageURL];
	[avatar setSize:NSMakeSize(24.0, 24.0)];
	[tmp setObject:avatar forKey:@"avatar"];
	[tmp setObject:[info objectForKey:@"screen_name"] forKey:@"title"];
	[avatar release];
	[self setUserInfo:[NSDictionary dictionaryWithDictionary:tmp]];
	[self loadStatuses];
	isLogined = YES;
	[msgBoard hide];
}


- (void)miscInfoReceived:(NSArray *)miscInfo forRequest:(NSString *)identifier
{
	//NSLog(@"Got misc info:\r%@", miscInfo);
}


- (void)imageReceived:(NSImage *)image forRequest:(NSString *)identifier
{
    //NSLog(@"Got an image: %@", image);
    
    // Save image to the Desktop.
    NSString *path = [[NSString stringWithFormat:@"~/Desktop/%@.tiff", identifier] 
                      stringByExpandingTildeInPath];
    [[image TIFFRepresentation] writeToFile:path atomically:NO];
}

#pragma mark Growl Delegate
- (NSDictionary *)registrationDictionaryForGrowl
{
	NSArray *theNotification = [NSArray arrayWithObject:growlShowNewStatuses];
	
	return [NSDictionary dictionaryWithObjectsAndKeys:
		theNotification, GROWL_NOTIFICATIONS_ALL,
		theNotification, GROWL_NOTIFICATIONS_DEFAULT, nil];
}

- (NSString *)applicationNameForGrowl
{
	return NSLocalizedString(@"APPNAME", @"CocoaFan");
}

@end
